package ro.peoplecentric.ctc.common.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import ro.peoplecentric.ctc.common.util.ui.SelectItemConvertible;

/**
 * Item entity.
 *
 * @author pguzun
 */
@Entity
@Table(name = "items")
public class Item implements Serializable, SelectItemConvertible {

    private static final long serialVersionUID = 42L;
    private static final String MSG_KEY_REQUIRED = "input.required";
    //
    public static final String NO_PHOTO = "no-photo.jpg";
    public static final Integer SHORT_DESCRIPTION_LENGTH = 255;
    //
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Long id;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 255)
    @Column(name = "title", length = 255)
    private String title;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 65535)
    @Column(name = "description", length = 65535)
    private String description;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 10)
    @Column(name = "postal_code", length = 10)
    private String postalCode;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 255)
    @Column(name = "name", length = 255)
    private String name;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 255)
    @Email
    @Column(name = "email", length = 255)
    private String email;
    @NotBlank(message = MSG_KEY_REQUIRED)
    @Size(max = 15)
    @Column(name = "phone", length = 15)
    private String phone;
    @Size(max = 255)
    @Column(name = "picture", length = 255)
    private String pictureUrl;
    @Column(name = "added")
    @Temporal(TemporalType.TIMESTAMP)
    private Date addedDate;
    @NotNull(message = MSG_KEY_REQUIRED)
    @Range(max = 999999999999l)
    @Column(name = "price")
    private Double price;
    @NotNull(message = MSG_KEY_REQUIRED)
    @ManyToOne(optional = false)
    @JoinColumn(name = "region_id", nullable = false)
    private Region region;
    @NotNull(message = MSG_KEY_REQUIRED)
    @ManyToOne(optional = false)
    @JoinColumn(name = "category_id", nullable = false)
    private Category category;
    @Column(name = "type")
    @Enumerated
    private ItemType type;

    public Item() {
        super();
        pictureUrl = NO_PHOTO;
        type = ItemType.Individual;
    }

    public Item(Long id) {
        super();
        this.id = id;
    }

    public Item(String name) {
        super();
        this.name = name;
    }

    @Override
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * @return the {@link Item#SHORT_DESCRIPTION_LENGTH short} description
     */
    public String getShortDescription() {
        String shortDescription;
        if ((description == null || description.length() <= SHORT_DESCRIPTION_LENGTH)) {
            shortDescription = description;
        } else {
            final StringBuilder sb = new StringBuilder();
            sb.append(description.substring(0, SHORT_DESCRIPTION_LENGTH));
            sb.append("...");
            shortDescription = sb.toString();
        }
        return shortDescription;
    }

    /**
     * @param description the description to set
     */
    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * @return the postalCode
     */
    public String getPostalCode() {
        return postalCode;
    }

    /**
     * @param postalCode the postalCode to set
     */
    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return the phone
     */
    public String getPhone() {
        return phone;
    }

    /**
     * @param phone the phone to set
     */
    public void setPhone(String phone) {
        this.phone = phone;
    }

    /**
     * @return the pictureUrl
     */
    public String getPictureUrl() {
        return pictureUrl;
    }

    /**
     * @param pictureUrl the pictureUrl to set
     */
    public void setPictureUrl(String pictureUrl) {
        this.pictureUrl = pictureUrl;
    }

    /**
     * @return the addedDate
     */
    public Date getAddedDate() {
        return addedDate;
    }

    /**
     * @param addedDate the addedDate to set
     */
    public void setAddedDate(Date addedDate) {
        this.addedDate = addedDate;
    }

    /**
     * @return the price
     */
    public Double getPrice() {
        return price;
    }

    /**
     * @param price the price to set
     */
    public void setPrice(Double price) {
        this.price = price;
    }

    /**
     * @return the region
     */
    public Region getRegion() {
        return region;
    }

    /**
     * @param region the region to set
     */
    public void setRegion(Region region) {
        this.region = region;
    }

    /**
     * @return the category
     */
    public Category getCategory() {
        return category;
    }

    /**
     * @param category the category to set
     */
    public void setCategory(Category category) {
        this.category = category;
    }

    /**
     * @return the type
     */
    public ItemType getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(ItemType type) {
        this.type = type;
    }

    @Override
    public int hashCode() {
        int hash = 7;
//WARNING!!! As Item entity does not have NaturalID I added id property to hashCode and equals
//This is a bad practice, but necessary.
//To the future Item must have NaturalID and id property must be removed from hashCode and equals !!!
        hash = 59 * hash + Objects.hashCode(this.getId());
        ///
        hash = 59 * hash + Objects.hashCode(this.getTitle());
        hash = 59 * hash + Objects.hashCode(this.getDescription());
        hash = 59 * hash + Objects.hashCode(this.getPostalCode());
        hash = 59 * hash + Objects.hashCode(this.getName());
        hash = 59 * hash + Objects.hashCode(this.getEmail());
        hash = 59 * hash + Objects.hashCode(this.getPhone());
        hash = 59 * hash + Objects.hashCode(this.getPictureUrl());
        hash = 59 * hash + Objects.hashCode(this.getAddedDate());
        hash = 59 * hash + Objects.hashCode(this.getPrice());
        hash = 59 * hash + Objects.hashCode(this.getRegion());
        hash = 59 * hash + Objects.hashCode(this.getCategory());
        hash = 59 * hash + Objects.hashCode(this.getType());
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Item)) {
            return false;
        }
        final Item other = (Item) obj;
//WARNING!!! As Item entity does not have NaturalID I added id property to hashCode and equals
//This is a bad practice, but necessary.
//To the future Item must have NaturalID and id property must be removed from hashCode and equals !!!
        if (!Objects.equals(this.getId(), other.getId())) {
            return false;
        }
        if (!isContentEquals(other)) {
            return false;
        }
        if (!isContactEquals(other)) {
            return false;
        }
        if (!Objects.equals(this.getAddedDate(), other.getAddedDate())) {
            return false;
        }
        if (!Objects.equals(this.getPrice(), other.getPrice())) {
            return false;
        }
        if (!Objects.equals(this.getRegion(), other.getRegion())) {
            return false;
        }
        if (!Objects.equals(this.getCategory(), other.getCategory())) {
            return false;
        }
        if (this.getType() != other.getType()) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Item{" + "id=" + id + ", title=" + title + ", description=" + description + ", postalCode=" + postalCode + ", name=" + name + ", email=" + email + ", phone=" + phone + ", pictureUrl=" + pictureUrl + ", addedDate=" + addedDate + ", price=" + price + ", region=" + region + ", category=" + category + ", type=" + type + '}';
    }

    private boolean isContactEquals(final Item other) {
        return (Objects.equals(this.getName(), other.getName())
                && Objects.equals(this.getEmail(), other.getEmail())
                && Objects.equals(this.getPhone(), other.getPhone())
                && Objects.equals(this.getPostalCode(), other.getPostalCode()));
    }

    private boolean isContentEquals(final Item other) {
        return (Objects.equals(this.getTitle(), other.getTitle()) && Objects.equals(this.getDescription(), other.getDescription()));
    }
}
